<!DOCTYPE HTML>
<html>

<head>
	<link rel="bookmark"  type="image/x-icon"  href="/img/logo.jpg"/>
	<link rel="shortcut icon" href="/img/logo.jpg">
	
			    <title>
    北望你的安
    </title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
    <link rel="stylesheet" href="/css/mic_main.css" />
    <link rel="stylesheet" href="/css/dropdownMenu.css" />
    <meta name="keywords" content="北望你的安" />
    
    	<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
	 
    <noscript>
        <link rel="stylesheet" href="/css/noscript.css" />
    </noscript>
    <style type="text/css">
        body:before {
          content: ' ';
          position: fixed;
          top: 0;
          background: url('/img/bg.jpg') center 0 no-repeat;
          right: 0;
          bottom: 0;
          left: 0;
          background-size: cover; 
        }
    </style>

			    
  


    <script src="/js/jquery.min.js"></script>
    <script src="/js/jquery.scrollex.min.js"></script>
    <script src="/js/jquery.scrolly.min.js"></script>
    <script src="/js/skel.min.js"></script>
    <script src="/js/util.js"></script>
    <script src="/js/main.js"></script>
	
</head>
    
		
<!-- Layouts -->



<!--  代码渲染  -->
<link rel="stylesheet" href="/css/prism_coy.css" />
<link rel="stylesheet" href="/css/typo.css" />
<!-- 文章页 -->
<body class="is-loading">
    <!-- Wrapper 外包 s-->
    <div id="wrapper" class="fade-in">
        <!-- Intro 头部显示 s -->
        <!-- Intro 头部显示 e -->
        <!-- Header 头部logo start -->
        <header id="header">
    <a href="/" class="logo">Krystalan</a>
</header>
        <!-- Nav 导航条 start -->
        <nav id="nav" class="special" >
            <ul class="menu links" >
			<!-- Homepage  主页  --> 
			<li >
	            <a href="/" rel="nofollow">主页</a>
	        </li>
			<!-- categories_name  分类   --> 
	        
	        <li class="active">
	            <a href="#s1">分类</a>
	                    <ul class="submenu">
	                        <li>
	                        <a class="category-link" href="/categories/%E5%BC%BA%E5%8C%96%E5%AD%A6%E4%B9%A0/">强化学习</a></li><li><a class="category-link" href="/categories/%E6%95%B0%E5%AD%A6/">数学</a></li><li><a class="category-link" href="/categories/%E7%AE%97%E6%B3%95/">算法</a></li><li><a class="category-link" href="/categories/%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7%90%86/">自然语言处理</a></li><li><a class="category-link" href="/categories/%E9%9A%8F%E7%AC%94/">随笔</a>
	                    </ul>
	        </li>
	        
	        <!-- archives  归档   --> 
	        
	        
		        <!-- Pages 自定义   -->
		        
		        <li>
		            <a href="/tags/" title="标签">
		                标签
		            </a>
		        </li>
		        
		        <li>
		            <a href="/gallery/" title="相册">
		                相册
		            </a>
		        </li>
		        


            </ul>
            <!-- icons 图标   -->
			<ul class="icons">
                    
                    <li>
                        <a title="github" href="https://github.com/krystalan" target="_blank" rel="noopener">
                            <i class="icon fa fa-github"></i>
                        </a>
                    </li>
                    
                    <li>
                        <a title="500px" href="https://www.zhihu.com/people/krystalzhu-an" target="_blank" rel="noopener">
                            <i class="icon fa fa-500px"></i>
                        </a>
                    </li>
                    
			</ul>
</nav>

        <div id="main" >
            <div class ="post_page_title_img" style="height: 25rem;background-image: url(/img/21.jpg);background-position: center; background-repeat:no-repeat; background-size:cover;-moz-background-size:cover;overflow:hidden;" >
                <a href="#" style="padding: 4rem 4rem 2rem 4rem ;"><h2 >PyTorch笔记（三）</h2></a>
            </div>
            <!-- Post -->
            <div class="typo" style="padding: 3rem;">
                <p>本文主要讲述的是pytorch当中的训练框架，并从中引出优化器以及损失函数的介绍。<br>这次举得例子比较简单，只是一个简单的线性模型，主要来初步尝试一下如何利用pytorch进行参数的学习。  </p>
<h1 id="1-线性回归"><a href="#1-线性回归" class="headerlink" title="1. 线性回归"></a>1. 线性回归</h1><p>在本节当中，以线性回归为例来介绍PyTorch训练参数的过程。</p>
<h2 id="1-1-问题定义"><a href="#1-1-问题定义" class="headerlink" title="1.1 问题定义"></a>1.1 问题定义</h2><p>给定一组x与y，利用线性回归去学习y与x之间的关系，假定服从：y = kx + b 。  </p>
<h2 id="1-2-数据"><a href="#1-2-数据" class="headerlink" title="1.2 数据"></a>1.2 数据</h2><pre><code class="python">import torch
import torch.optim as optim
x = [35.7,55.9,58.2,81.9,56.3,48.9,33.9,21.8,48.4,60.4,68.4]
y = [0.5,14.0,15.0,28.0,11.0,8.0,3.0,-4.0,6.0,13.0,21.0]
x = torch.tensor(x)
y = torch.tensor(y)</code></pre>
<h2 id="1-3-模型、参数与损失函数"><a href="#1-3-模型、参数与损失函数" class="headerlink" title="1.3 模型、参数与损失函数"></a>1.3 模型、参数与损失函数</h2><pre><code class="python">def model(x,w):
    return x*w[0]+w[1]

def loss_fn(x,y):
    return torch.mean((x-y)*(x-y))

params = torch.tensor([1.0,0.0],requires_grad=True)#线性模型参数</code></pre>
<h2 id="1-4-优化器"><a href="#1-4-优化器" class="headerlink" title="1.4 优化器"></a>1.4 优化器</h2><pre><code class="python">learning_rate = 1e-4
optimizer = optim.SGD([params],lr=learning_rate)</code></pre>
<p>这里直接选择了SGD</p>
<h2 id="1-5-训练过程"><a href="#1-5-训练过程" class="headerlink" title="1.5 训练过程"></a>1.5 训练过程</h2><h3 id="1-5-1-未加验证集"><a href="#1-5-1-未加验证集" class="headerlink" title="1.5.1 未加验证集"></a>1.5.1 未加验证集</h3><pre><code class="python">train_y = model(x,params)
k = loss_fn(train_y,y)+1 #利用k来保存上一步的loss

while True:
    train_y = model(x,params)#获取当前预测值
    loss = loss_fn(train_y,y)#根据当前预测值计算loss

    optimizer.zero_grad()#在反向传播前清除梯度，否则将累积梯度
    loss.backward()#反向传播
    optimizer.step()#利用优化器更新参数，也就是更新params
    print(loss)
    if k - loss &lt; 0.0000001: #当loss在一步中降低的值低于某阈值就停止学习
        break
    else:
        k = loss
print(params)</code></pre>
<h3 id="1-5-2-加入验证集"><a href="#1-5-2-加入验证集" class="headerlink" title="1.5.2 加入验证集"></a>1.5.2 加入验证集</h3><p>（1）数据处理：将数据集中20%作为验证集，80%作为训练集。</p>
<pre><code class="python">x = [35.7,55.9,58.2,81.9,56.3,48.9,33.9,21.8,48.4,60.4,68.4]
y = [0.5,14.0,15.0,28.0,11.0,8.0,3.0,-4.0,6.0,13.0,21.0]
x = torch.tensor(x)
y = torch.tensor(y)

n_samples = x.shape[0]
n_val = int(0.2*n_samples)

shuffled_indices = torch.randperm(n_samples)

train_indices = shuffled_indices[:-n_val]
val_indices = shuffled_indices[-n_val::]

train_x = x[train_indices]
train_y = y[train_indices]

val_x = x[val_indices]
val_y = y[val_indices]</code></pre>
<p>（2）设置优化器（这里选了Adam优化器）：</p>
<pre><code class="python">params = torch.tensor([1.0,0.0],requires_grad=True)
learning_rate = 1e-2
optimizer = optim.Adam([params],lr=learning_rate)</code></pre>
<p>（3）训练过程：</p>
<pre><code class="python">val_y2 = model(val_x,params)
k = loss_fn(val_y2,val_y)+1
t = 0
while True:
    train_y2 = model(train_x,params)
    train_loss = loss_fn(train_y2,train_y)

    with torch.no_grad():#在如下计算当中不记参数梯度，如果不加这部分直接计算的会，系统会继续计算梯度，虽然不会对结果产生影响，但会浪费内存和计算效率。
        val_y2 = model(val_x,params)
        val_loss = loss_fn(val_y2,val_y)

    optimizer.zero_grad()
    train_loss.backward()
    optimizer.step()
    print(&#39;train_loss:&#39;+str(train_loss)+&#39;\t&#39;+&#39;val_loss:&#39;+str(val_loss))
    if k - val_loss &gt;0:
        t = max(0,t-1)
        k = val_loss
    else:
        t+=1
        k = val_loss
        if t == 5:
            break

print(params)</code></pre>
<p>这里在训练中，如果验证集连续五次的loss都上升则停止训练。<br>需要注意的是，这里为了高效性使用了<strong>with torch.no_grad()</strong>，在该代码内的计算过程将不会追踪梯度。</p>
<h1 id="2-优化器"><a href="#2-优化器" class="headerlink" title="2. 优化器"></a>2. 优化器</h1><p>在第一节的介绍当中，我们使用了两个优化器，分别是SGD与Adam：  </p>
<pre><code class="python">import torch.optim as optim
learning_rate = 1e-5
optimizer1 = optim.SGD([params],lr=learning_rate)
optimizer2 = optim.Adam([params],lr=learning_rate)</code></pre>
<p>这节主要探讨一下torch.optim</p>
<blockquote>
<p>官方文档的解读：torch.optim is a package implementing various optimization algorithms. Most commonly used methods are already supported, and the interface is general enough, so that more sophisticated ones can be also easily integrated in the future.</p>
</blockquote>
<h2 id="2-1-如何构建优化器"><a href="#2-1-如何构建优化器" class="headerlink" title="2.1 如何构建优化器"></a>2.1 如何构建优化器</h2><p>在使用构建优化器的时候，你需要告诉优化器你想要优化的参数有哪些，通常就是模型的参数，并且为优化器设置一些超参数，例如learning rate等，不同优化器的超参数不同。<br>例如：  </p>
<pre><code class="python">optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)</code></pre>
<p>这里使用到了带动量的SGD，构建优化器的第一个输入就是所训练的模型的全部参数。 </p>
<p>需要注意的是：如果你在GPU上炼丹，那你要在构建优化器之前，就把模型先移动到GPU上。  </p>
<h2 id="2-2-如何使用优化器"><a href="#2-2-如何使用优化器" class="headerlink" title="2.2 如何使用优化器"></a>2.2 如何使用优化器</h2><p>非常常用的有两个方法，分别是<strong>zero_grad()</strong>和<strong>step()</strong>，我们截取第一节中的例子来看一下：  </p>
<pre><code class="python">while True:
    train_y = model(x,params)#获取当前预测值
    loss = loss_fn(train_y,y)#根据当前预测值计算loss

    optimizer.zero_grad()#在反向传播前清除梯度，否则将累积梯度
    loss.backward()#反向传播
    optimizer.step()#利用优化器更新参数，也就是更新params</code></pre>
<p>zero_grad()用于清除当前累积的梯度，pytorch在训练的过程当中，并不会因为调用step()函数更新参数之后就清除掉当前步的梯度，因为这样不够灵活，累积梯度在某些情况下是有用的。所以我们在每次反向传播之前，经常会调用zero_grad()方法来清除之前累积的梯度。  </p>
<p>step()函数用于更新构建优化器时传入的模型参数。</p>
<h2 id="2-3-有哪些优化器"><a href="#2-3-有哪些优化器" class="headerlink" title="2.3 有哪些优化器"></a>2.3 有哪些优化器</h2><h3 id="2-3-1-SGD"><a href="#2-3-1-SGD" class="headerlink" title="2.3.1 SGD"></a>2.3.1 SGD</h3><pre><code class="python">torch.optim.SGD(params, lr=&lt;required parameter&gt;, momentum=0, dampening=0, weight_decay=0, nesterov=False)</code></pre>
<p>PyTorch中的SGD带有momentum与nesterov，momentum会考虑之前的动量来对本次梯度做出大小方面的调整指导SGD在该跑的时候跑，在该慢的时候慢，如果开启nesterov则不仅考虑之前的动量大小，还考虑动量方向。dampening是动量的衰减，weight_decay是衰减（L2正则）系数。  </p>
<h3 id="2-3-2-Adam"><a href="#2-3-2-Adam" class="headerlink" title="2.3.2 Adam"></a>2.3.2 Adam</h3><p>（1）Adam</p>
<pre><code class="python">torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0, amsgrad=False)</code></pre>
<p>eps是增加分母以提高数值稳定性的项，amsgrad是选择是否启用Adam的另一个变体版本AMSGrad。<br>（2）Adamw<br>Adamw：<a href="https://arxiv.org/abs/1711.05101" target="_blank" rel="noopener">https://arxiv.org/abs/1711.05101</a></p>
<pre><code class="python">torch.optim.AdamW(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0.01, amsgrad=False)</code></pre>
<p>（3）Adamax<br>基于无穷范数的Adam的一个变种</p>
<pre><code class="python">torch.optim.Adamax(params, lr=0.002, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)</code></pre>
<p>（4）SparseAdam<br>适用于稀疏张量的Adam算法的懒惰版本。在这个变体中，只有在渐变中出现的时刻才会更新，只有渐变的那些部分才会应用于参数。</p>
<pre><code class="python">torch.optim.SparseAdam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08)</code></pre>
<h3 id="2-3-3-其余"><a href="#2-3-3-其余" class="headerlink" title="2.3.3 其余"></a>2.3.3 其余</h3><pre><code class="python">torch.optim.Adadelta(params, lr=1.0, rho=0.9, eps=1e-06, weight_decay=0)
torch.optim.Adagrad(params, lr=0.01, lr_decay=0, weight_decay=0, initial_accumulator_value=0, eps=1e-10)
torch.optim.ASGD(params, lr=0.01, lambd=0.0001, alpha=0.75, t0=1000000.0, weight_decay=0)## Averaged Stochastic Gradient Descent
torch.optim.LBFGS(params, lr=1, max_iter=20, max_eval=None, tolerance_grad=1e-07, tolerance_change=1e-09, history_size=100, line_search_fn=None)
torch.optim.RMSprop(params, lr=0.01, alpha=0.99, eps=1e-08, weight_decay=0, momentum=0, centered=False)
torch.optim.Rprop(params, lr=0.01, etas=(0.5, 1.2), step_sizes=(1e-06, 50))</code></pre>
<h1 id="3-损失函数"><a href="#3-损失函数" class="headerlink" title="3. 损失函数"></a>3. 损失函数</h1><p>在第一节中，我们自己定义了一个损失函数，如下：  </p>
<pre><code class="python">def loss_fn(x,y):
    return torch.mean((x-y)*(x-y))</code></pre>
<p>但其实在torch中，是有定义好的损失函数可以直接拿来用的，损失函数存在于torch.nn当中：<br><img src="/images/pytorch/3.jpg" alt="torch.nn">   </p>
<h2 id="3-1-L1loss"><a href="#3-1-L1loss" class="headerlink" title="3.1 L1loss"></a>3.1 L1loss</h2><p>绝对值损失，返回output与target绝对值之差的均值：  </p>
<pre><code class="python">target = torch.tensor([1.5,2.0,3.0,4.0])
output = torch.tensor([0.0,1.0,2.0,3.0])
loss_function = nn.L1Loss()
loss = loss_function(target,output)
print(loss)</code></pre>
<p>输出为：</p>
<pre><code class="python">tensor(1.1250)</code></pre>
<h2 id="3-2-MSELoss"><a href="#3-2-MSELoss" class="headerlink" title="3.2 MSELoss"></a>3.2 MSELoss</h2><p>平方损失，返回output与target的之差的平方的均值：    </p>
<pre><code class="python">target = torch.tensor([1.5,2.0,3.0,4.0])
output = torch.tensor([0.0,1.0,2.0,3.0])
loss_function = nn.MSELoss()
loss = loss(target,output)
print(loss)</code></pre>
<p>输出为：</p>
<pre><code class="python">tensor(1.3125)</code></pre>
<h2 id="3-3-CrossEntropyLoss"><a href="#3-3-CrossEntropyLoss" class="headerlink" title="3.3 CrossEntropyLoss"></a>3.3 CrossEntropyLoss</h2><p>交叉熵损失函数：先将预测结果进行softmax之后在进行熵的计算。<br>假设一个三分类的任务，我们预测的结果为分别为：-999，-100与1，这三个值经过softmax之后的结果就分别对应类别0,1,2的预测概率，其真实结果为2，于是我们通过下式计算其交叉熵：  </p>
<pre><code class="python">loss_function = nn.CrossEntropyLoss()
output = torch.tensor([[-999.0,-100.0,1.0]])
target = torch.tensor([2])
loss = loss_function(output,target)
print(loss)</code></pre>
<p>输出为：</p>
<pre><code class="python">tensor(0.)</code></pre>
<p>我们也可以一次性输入多条数据与其对应真实结果，该损失函数会返回所有数据的平均熵：  </p>
<pre><code class="python">loss_function = nn.CrossEntropyLoss()
output = torch.tensor([[-999.0,-100.0,1.0],[1.0,1.0,1.0]])
target = torch.tensor([2,1])
loss = loss_function(output,target)
print(loss)</code></pre>
<p>输出为：</p>
<pre><code class="python">tensor(0.5493)</code></pre>
<h2 id="3-4-其余"><a href="#3-4-其余" class="headerlink" title="3.4 其余"></a>3.4 其余</h2><p>其余损失函数可以参考以下两个链接这里就不多赘述了。<br>相关介绍：<a href="https://zhuanlan.zhihu.com/p/61379965" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/61379965</a><br>官方文档：<a href="https://pytorch.org/docs/stable/nn.html#loss-functions" target="_blank" rel="noopener">https://pytorch.org/docs/stable/nn.html#loss-functions</a>  </p>

            </div>

            <!-- Post Comments -->
            

        </div>
        <!-- Copyright 版权 start -->
                <div id="copyright">
            <ul>
                <li>&copy;2020 北望你的安. 版权所有</li>
            </ul>
            
                <span id="busuanzi_container_site_pv">本站总访问量<span id="busuanzi_value_site_pv"></span>次，</span>
				<span id="busuanzi_container_site_uv"> 访客数 <span id="busuanzi_value_site_uv"></span> 人. </span>
			
			<br>
			<span>友情链接：<a href='http://www.demilab.cn' target='_blank'>DEMI实验室</a>&nbsp;&nbsp;&nbsp;<a href='http://zd11024.cn/' target='_blank'>ZD</a></span>
        </div>
    </div>
</body>



 	
</html>
